from __future__ import absolute_import, unicode_literals
import rsa
import Crypto
import requests
import base64
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA
from Crypto.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
from Crypto.Cipher import PKCS1_v1_5  # 用于加密/ 解密
from core.tools.custom_requests import CustomRequests
from finance_c2c.local_settings import ONLINE, Config


class BaseTLClient(CustomRequests):
    _http = requests.Session()

    def __init__(self, appid, mch_id, base_url, private_key=None, pkcs1_rsa_public=None):
        """
        :param appid:
        :param mch_id:
        :param base_url:
        :param private_key:  秘钥 通过pfx文件提取出来的秘钥
        :param pkcs8_rsa_public_h5: 通联H5公钥
        :param public_key: 提取出来的公钥
        """
        self.appid = appid
        self.mch_id = mch_id
        self.base_url = base_url
        self.private_key = private_key
        self.pkcs1_rsa_public = pkcs1_rsa_public

    def token_key(self, user_id):
        """
        :param user_id: 自己系统的用户id
        :return:
        """
        if ONLINE:
            key = 'ONLINE_tl_{appId}_{user_id}_token'.format(**{"appId": self.appid, "user_id": user_id})
            print(key)
            return key
        else:
            key = 'test_tl_{appId}_{user_id}_token'.format(**{"appId": self.appid, "user_id": user_id})
            print(key)
            return key

    def to_sign_with_private_key(self, content):
        """
        签名
        :param content:
        :return:
        """
        with open(self.private_key, 'rb') as private_file:
            # 私钥的绝对路径
            keydata = private_file.read()
        privatekey = rsa.PrivateKey.load_pkcs1(keydata)
        signature = rsa.sign(content.encode('utf-8'), privatekey, 'SHA-1')
        sign = base64.b64encode(signature).decode('utf-8')
        return sign

    def encrypt_with_rsa(self, content):
        # 公钥加密
        with open(self.pkcs1_rsa_public, 'rb') as public_file:
            publicKeyBytes = public_file.read()
        pub = RSA.import_key(publicKeyBytes)
        cipher = PKCS1_v1_5.new(pub)
        encrypt_bytes = cipher.encrypt(content.encode(encoding='utf-8'))
        result = base64.b64encode(encrypt_bytes)
        result = str(result, encoding='utf-8')
        return result

    def get_max_length(self, rsa_key, encrypt=True):
        """加密内容过长时 需要分段加密 换算每一段的长度.
            :param rsa_key: 钥匙.
            :param encrypt: 是否是加密.
        """
        blocksize = Crypto.Util.number.size(rsa_key.n) / 8
        reserve_size = 11  # 预留位为11
        if not encrypt:  # 解密时不需要考虑预留位
            reserve_size = 0
        maxlength = blocksize - reserve_size
        return maxlength

    # 私钥解密
    def decrypt_with_rsa(self, encrypt_message):  # 解密
        with open(self.private_key, 'rb') as privatefile:
            p = privatefile.read()
        privkey = rsa.PrivateKey.load_pkcs1(p)
        lase_text = rsa.decrypt(encrypt_message, privkey).decode()  # 注意，这里如果结果是bytes类型，就需要进行decode()转化为str
        return lase_text

    # 非联合登陆验签
    def to_verify_with_public_key(self, signature, plain_text):
        # 公钥验签
        with open(self.pkcs1_rsa_public, 'rb') as privatefile:
            # 私钥的绝对路径
            public_key_file = privatefile.read()
        public_key = RSA.importKey(public_key_file)
        verifier = Signature_pkcs1_v1_5.new(public_key)
        digest = SHA.new()
        digest.update(plain_text.encode())
        signature = base64.b64decode(signature)  # 区别 base64decode 一遍
        result = verifier.verify(digest, signature)
        return result

    # 联合登录验签
    def Oauth_verify_with_public_key(self, signature, plain_text, cid):
        # 公钥验签
        pkcs1_rsa_public = Config.VerBook.get(cid)
        print(pkcs1_rsa_public, "rsa public")
        public_key = RSA.importKey(pkcs1_rsa_public)
        verifier = Signature_pkcs1_v1_5.new(public_key)
        digest = SHA.new()
        digest.update(plain_text.encode())
        signature = base64.b64decode(base64.b64decode(signature))  # 区别 base64decode两遍
        result = verifier.verify(digest, signature)
        print(result, "Oauth_verify_with_public_key")
        return result

    @classmethod
    def sign_msg_stored(cls, request_params, base_sorted=None):
        list_l = []
        if not base_sorted:
            base_sorted = ['version', 'signType', 'appId', 'merchantId', "merchantUserId", 'accountType', 'mobileNo',
                           'registerSource', 'requestDatetime']
        for i, k in enumerate(base_sorted):
            if i == 0:
                str1 = k + "=" + request_params[k]
                list_l.append(str1)
            else:
                if k in request_params and request_params[k]:
                    str2 = "&" + str(k) + "=" + str(request_params[k])
                    list_l.append(str2)
        content = ''.join([str(i) for i in list_l])
        return content

    @classmethod
    def get_source_string(cls, parameters, base_sorted=None):
        """
        企业付款生成source节点字符串
        :param parameters:
        :param base_sorted:
        :return:
        """
        if not base_sorted:
            base_sorted = sorted(parameters)
        source = ""
        for i in base_sorted:
            if parameters[i] and isinstance(parameters[i], str):
                source += parameters[i]
        return source

    @classmethod
    def get_source_add_key(cls, parameters, base_sorted=None):
        """
        企业付款生成source节点字符串
        :param parameters:
        :param base_sorted:
        :return:
        """
        if not base_sorted:
            base_sorted = sorted(parameters)
        source = []
        for i in base_sorted:
            source.append(i + '=' + parameters[i] if parameters[i] else "")
        print(source, "list")
        return '&'.join(source)

    @classmethod
    def parameters_put(cls, parameters):
        data = dict()
        for i in parameters:
            if parameters[i]:
                data[i] = parameters[i]
        return data

    def to_verify_with_public_key_1(self, signature, plain_text):
        # 公钥验签
        with open(self.pkcs1_rsa_public, 'rb') as privatefile:
            # 私钥的绝对路径
            public_key_file = privatefile.read()
        public_key = RSA.importKey(public_key_file)
        verifier = Signature_pkcs1_v1_5.new(public_key)
        digest = SHA.new()
        digest.update(plain_text.encode())
        is_verify = verifier.verify(digest, base64.b64decode(signature))
        print(is_verify, "非Oauth公钥验签")
        return is_verify
